-- 2.
-- I

curry' :: ((a,b) -> c) -> a -> b -> c
curry' f = \x y -> f (x,y)

-- II
uncurry' :: (a -> b -> c) -> (a,b) -> c
uncurry' f = \(x,y) -> f x y

-- 4
pitagoricas = [ (x,y,z) | n <- [0..], x <- [0..n], y <- [0..n-x], z <- [n-x-y], x^2 + y^2 == z^2 ]


-- 6

partir :: [a] -> [([a], [a])]
partir [] = [([], [])]
partir (x:xs) = ([],x:xs) : map (\(h,t) -> (x:h,t)) (partir xs)

{--
foldr :: (a -> b -> b) -> b -> [a] -> b
miFoldr :: (a -> [([a],[a])] -> [([a],[a])]) -> [([a],[a])] -> [a] -> [([a],[a])]
--}
partir2 :: [a] -> [([a], [a])]
partir2 = foldr partirRecursivo [([],[])]

partirRecursivo :: a -> [([a],[a])] -> [([a],[a])]
partirRecursivo x l = ( [] , x:(pegar (head l)) ) : (map (\(h,t) -> (x:h,t)) l)

pegar :: ([a],[a]) -> [a]
pegar par = fst par ++ snd par


-- Me parece que se pretendía algo así:
partir3 :: [a] -> [([a], [a])]
partir3 l = [ (take n l, drop n l) | n <- [0..length l] ]


-- 7

listasQueSuman :: Int -> [[Int]]
listasQueSuman 0 = [[]]
listasQueSuman n = [ (i:xs) | i <- [1..n], xs <- listasQueSuman (n-i) ]


-- 8

todas = [ xs | n <- [1..], xs <- listasQueSuman n]


-- 9
-- I

sum :: Num a => [a] -> a
sum = foldr (+) 0 

elem :: Eq a => a -> [a] -> Bool
elem x = foldr (\y res -> x == y || res) False

plus :: [a] -> [a] -> [a]
plus = flip (foldr (\y res -> (y:res)))

filter' :: (a -> Bool) -> [a] -> [a]
filter' f = foldr (\x res -> if f x then (x:res) else res) []

map' :: (a -> b) -> [a] -> [b]
map' f = foldr (\x res -> (f x:res)) []


-- II

sumaAlt :: Num a => [a] -> a
sumaAlt = fst . (foldr (\x (res,s) -> (s*x + res, s * (-1))) (0,1))
-- Fruta, anda mal...
--sumaAlt :: Num a => [a] -> a
--sumaAlt = fst . (foldr (\x (res,s) -> (s*x + res, s * -1)) (0,1))
--sumaAlt l = foldr (\x res -> x + res) 0 [ if i `mod` 2 == 0 then (l !! i) else -(l !! i) | i <- [0..length l - 1] ]

sumaAltR :: Num a => [a] -> a
sumaAltR l = foldr (\(x,s) res -> x * s + res) 0 (reverse [ (l !! i, if i `mod` 2 == 0 then 1 else -1) | i <- [0..length l - 1] ])


-- 10
-- I

partes :: [a] -> [[a]]
--partes [] = [[]]
--partes (x:xs) = [ (x:p) | p <- partes xs ] ++ partes xs
partes = foldr (\x ps -> [ (x:p) | p <- ps ] ++ ps) [[]]

-- II

prefijos :: [a] -> [[a]]
prefijos = foldr (\x ps -> ([]:[ (x:p) | p <- ps ])) [[]]

-- III

sublistas :: [a] -> [[a]]
sublistas = recr [[]] (\x xs r -> r ++ [ (x:p) | p <- prefijos xs ])
--sublistas [] = [[]]
--sublistas xxs@(x:xs) = sublistas xs ++ f xxs
--	where f = \x xs -> [ (x:p) | p <- prefijos xs ]

recr :: b -> (a -> [a] -> b -> b) -> [a] -> b
recr base _ [] = base
recr base f (x:xs) = f x xs (recr base f xs)


-- 13
-- I

mapPares :: (a -> b -> c) -> [(a,b)] -> [c]
mapPares f = map (uncurry f)

-- II

armarPares :: [a] -> [b] -> [(a,b)]
armarPares [] _ = []
armarPares _ [] = []
armarPares (x:xs) (y:ys) = ( (x,y) : armarPares xs ys )

armarPares' :: [a] -> [b] -> [(a,b)]
armarPares' = foldr (\x rec -> (\l -> case l of [] -> []; (y:ys) -> ((x,y) : rec ys))) (const [])

-- 13
-- III

mapDoble :: (a -> b -> c) -> [a] -> [b] -> [c]
mapDoble f = foldr (\x rec l -> case l of (y:ys) -> (f x y):(rec ys)) (const [])

-- 19
-- IV
type Conj a = a -> Bool

vacio :: Conj a
vacio = const False

agregar :: Eq a => a -> Conj a -> Conj a
agregar e c = \x -> x == e || (c x)

primeraAparicion :: a -> [Conj a] -> Int
primeraAparicion e cs = length (takeWhile  (\c ->  not (c e)) cs)
